<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>首页</title>
		<img id="myImg" src="https://avatar-static.segmentfault.com/925/449/925449377-5bbd6a9af172b_big64" alt="">
		<link href="https://cdn.bootcss.com/bootstrap/4.0.0-alpha.6/css/bootstrap.css" rel="stylesheet">
	</head>
	<body>
		<div id="app text-primary">
			<p>
				<button type="button" id="btn" class="btn btn-primary">（首选项）Primary</button>
			</p>
			<p>1</p>
			<p>1</p>
			<p>1</p>
			<p>1</p>
			<p>1</p>
		</div>
		<script type="text/javascript">
			(function(root) {
				const rejectExp = /^<(\w+)>(?:<\/\1>|)$/;
				const core_version = 'v1.1.1';
				const jQuery = function(selector, context) {
					return new jQuery.fn.init(selector, context);
				}

				jQuery.fn = jQuery.prototype = {
					length: 0,
					selector: '',
					init: function(selector, context) {
						context = context || document;
						let match, elem;

						if (!selector) {
							return this;
						}

						if (typeof selector === "string") {

							if (selector[0] === "<" && selector[selector.length - 1] === ">" && selector.length >= 3) {
								match = [selector];
							}
							if (match) {
								jQuery.merge(this, jQuery.parseHTML(selector, context))
							} else {
								elem = context.querySelectorAll(selector);
								let elems = [].slice.call(elem);
								jQuery.merge(this, elems)
								this.context = context;
								this.selector = selector;
							}

						} else if (selector.nodeType) {
							// 判断是否为DOM元素 例如 $(document) 原生dom和jQuery对象的转换
							this[0] = selector;
							this.length = 1;
							return this;
						}
					}
				}

				jQuery.fn.extend = jQuery.extend = function() {
					let first = arguments[0] || {},
						length = arguments.length,
						i = 1,
						options,
						deep,
						copy, src, copyIsArray, clone;

					if (typeof first === 'boolean') {
						deep = first;
						first = arguments[i++];
					}

					if (typeof first !== 'object') {
						first = {};
					}

					if (length === i) {
						first = this;
						i--;
					}

					for (; i < length; i++) {
						if ((options = arguments[i]) != null) {
							for (let key in options) {
								copy = options[key];
								src = first[key];
								// 这里需要把deep放在前面,这样当deep为false的时候就不会执行后面的代码
								// 所以在后面调用jQuery.extend给jQuery扩展isPlainObject等方法时就不会报错
								if (deep && (jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)))) {
									if (copyIsArray) {
										copyIsArray = false;
										clone = (src && jQuery.isArray(src)) ? src : []
									} else {
										clone = (src && jQuery.isPlainObject(src)) ? src : {};
									}
									first[key] = jQuery.extend(deep, clone, copy)
								} else if (copy != undefined) {
									first[key] = copy;
								}
							}
						}
					}
					return first;
				}

				jQuery.extend({
					expando: 'jQuery' + (core_version + Math.random()).replace(/\D/g, ''),
					guid: 1,
					each: function(object, callback, args) {
						let length = object.length,
							name, i = 0;

						if (length === undefined) {
							if (args) {
								for (name in object) {
									callback.apply(object, args)
								}
							} else {
								for (name in object) {
									callback.call(object, name, object[name])
								}
							}
						} else {
							if (args) {
								for (; i < length;) {
									callback.apply(object[i++], args)
								}
							} else {
								for (; i < length;) {
									callback.call(object[i], i, object[i++])
								}
							}
						}
					},
					isPlainObject: function(obj) {
						return toString.call(obj) === '[object Object]'
					},
					isArray: function(obj) {
						return toString.call(obj) === '[object Array]'
					},
					merge: function(first, second) {
						let len = second.length,
							j = 0,
							i = first.length;
						if (typeof len === 'number') {
							for (; j < len; j++) {
								first[i++] = second[j];
							}
						} else {
							while (second[j] !== undefined) {
								first[i++] = second[j++];
							}
						}
						first.length = i;
						return first;
					},
					parseHTML: function(data, context) {
						if (!data || typeof data !== 'string') {
							return []
						}
						let parse = rejectExp.exec(data)[1];
						return [context.createElement(parse)];
					}
				})

				// jQuery.extend({
				// 	Callbacks: function () {
				// 		console.log('extend Callbacks');
				// 	}
				// })
				jQuery.Callbacks = function(options) {
					options = (typeof options === 'string') ? createOptions(options) : jQuery.extend({}, options);

					let list = [],
						index = 0,
						length,
						memory, once,
						fire = function(data) {
							once = once || options.once;
							memory = options.memory && data;
							length = list.length;
							console.log();
							for (; index < length; index++) {
								if (list[index].apply(data[0], data[1]) === false && options.stopOnfalse) {
									break;
								}
							}
						},
						self = {
							add: function(...args) {
								args.forEach(item => {
									if (typeof item === 'function') {
										list.push(item);
									}
								})
								memory && fire(memory);

								return this;
							},
							fireWith: function(context, args) {
								if (!once) {
									fire([context, args]);
								}
								return this;
							},
							fire: function() {
								this.fireWith(this, arguments);
								return this;
							}
						}
					return self;
				}

				function createOptions(options) {
					let object = {};
					options.split(/\s+/).forEach(val => {
						object[val] = true;
					})
					return object;
				}

				function Data() {
					this.expando = jQuery.expando + Math.random();
					this.cache = {};
					/*
						最终经过注册事件之后
						cache: {
							1: {
								events: {
									'click': [
										{
											type: 'click',
											handler: function(){},
											guid: 1
										},
										delegateCount: 0
									]
								},
								// handle.elem = elem;
								handle: function (e) {
									return jQuery.event.dispatch.apply(eventHandle.elem, arguments);
								}
							},
							...
						}
					*/
				}
				Data.uid = 1;
				Data.prototype = {
					key: function(elem) {
						let descriptor = {},
							unlock = elem[this.expando];
						// 找到这个元素上的expando属性,elem.jQuery12839749123782: 1,如果这个元素注册过他就会有这个属性

						if (!unlock) {
							unlock = Data.uid++;
							descriptor[this.expando] = {
								value: unlock
							}
							// 给elem扩展this.expando的属性 即elem.jQuery12839749123782: 1
							Object.defineProperties(elem, descriptor);
						}
						if (!this.cache[unlock]) {
							this.cache[unlock] = {}
						}
						// 最终返回unlock, 可通过 this.cache[unlock] 获取其数据对象
						// unlock === elem.jQuery12839749123782
						return unlock;
					},
					get: function(elem, key) {
						let cache = this.cache[this.key(elem)];
						return key === undefined ? cache : cache[key];
					}
				}
				var data_priv = new Data();
				jQuery.event = {
					add: function(elem, type, handler) {
						let events, eventHandle, handlers;

						let elemData = data_priv.get(elem); // 获取elem 的数据对象

						if (!handler.guid) {
							handler.guid = jQuery.guid++; // 给事件函数添加一个guid,目的是为了方便找到这个函数？
						}

						/*
							给缓存的事件对象添加事件处理句柄（属性）
							elemData:{
								events: {},
								handle: function(){}
							}
						*/
						if (!(events = elemData.events)) {
							events = elemData.events = {};
						}
						if (!(eventHandle = elemData.handle)) {
							eventHandle = elemData.handle = function(e) {
								return jQuery.event.dispatch.apply(eventHandle.elem, arguments);
							};
						}
						eventHandle.elem = elem;

						if (!(handlers = events[type])) {
							handlers = events[type] = [];
							handlers.delegateCount = 0; //计算这个类型的事件数量
						}
						handlers.push({
							type: type,
							handler: handler,
							guid: handler.guid
						})

						if (elem.addEventListener) {
							elem.addEventListener(type, eventHandle, false);
						}
					},
					dispatch: function(event, data) {
						// event 就是事件触发后的e参数 elem.addEventListener('click',function( e ){})
						// 所以 event.type 就会告诉你触发的是什么类型的事件
						let handlers = (data_priv.get(this, 'events') || {})[event.type] || [];
						console.log(handlers);
						event.delegateTarget = this; // 这里是干嘛的
						jQuery.event.handlers.call(this, event, handlers, data)
					},
					handlers: function(event, handlers, data) {
						// 为什么只触发1个事件呢
						handlers[0].handler.call(this, event, data);
					},
					spacial: {
						click: {
							trigger: function() {
								if (this.type === 'checkbox' && this.click && jQuery.nodeName(this, 'input')) {
									this.click();
									return false;
								}
							},
							_default: function(event) {
								return jQuery.nodeName(event.target, 'a')
							}
						}
					},
					trigger: function(event, data, elem) {
						let i = 0,
							eventPath = [elem || document],
							type = event.type || event,
							cur = tmp = elem = elem || dpcument,
							ontype = /^\w+$/.test(type) && 'on' + type;

						console.log(ontype);
						// 整个event模拟的就是在事件触发时传入的 e 参数 function(e){...};
						event = event[jQuery.expando] ? event : new jQuery.Event(type, typeof event === 'object' && event);

						if (!event.target) { // 给evnet扩展一个target属性
							event.target = elem
						}

						// 最终这个data就是事件触发时传入的所有参数,所以第一个参数是event
						data = data == null ? [event] : [event, data];

						// 虽然trigger可执行自定义事件,但是当它执行的是click,focus等本来就存在的事件时
						// 用spacial来记录这些事件,并处理
						spacial = jQuery.event.spacial[type] || {};
						// 找到改事件的trigger方法,并执行;如果返回一个false则停止后面代码（自定义冒泡）的执行
						if (spacial.trigger && spacial.trigger.apply(elem, data) === false) {
							return;
						}
						// 循环获取elem的父元素并存到eventPath中
						cur = cur.parentNode;
						for (; cur; cur = cur.parentNode) {
							eventPath.push(cur);
							tmp = cur;
						}

						if (tmp === (elem.ownerDocument || document)) { // 将window作为exentPath最后一个元素
							eventPath.push(tmp.defaultView || tmp.parentWindow || window);
						}

						while ((cur = eventPath[i++])) {
							handle = (data_priv.get(cur, 'events') || {})[event.type] && data_priv.get(cur, 'handle');
							if (handle) {
								// handle: function (e) {
								// 	return jQuery.event.dispatch.apply(eventHandle.elem, arguments);
								// }
								console.log(data);
								handle.apply(cur, data)
							}
						}
					}
				}

				jQuery.Event = function(src, props) {
					// 如果this不是jQuery.Event的实例对象,则返回一个实例对象
					// 例如在这种情况下: var obj = jQuery.Event(src, props); 
					if (!(this instanceof jQuery.Event)) {
						return new jQuery.Event(src, props);
					}

					this.type = src;
					this.timeStamp = src && src.timeStamp || Date.now();
					this[jQuery.expando] = true;
				}
				jQuery.Event.prototype = {
					isDefaultPrevented: false,
					isPropagationStopped: false,
					isImmediatePropagationStopped: false,
					// 取消事件的默认动作
					preventDefault: function() {
						let e = this.originalEvent;
						this.isDefaultPrevented = true;
						if (e && e.preventDefault) {
							e.preventDefault();
						}
					},
					// 阻止冒泡到父元素
					stopPropagation: function() {
						let e = this.originalEvent;
						this.isPropagationStopped = true;
						if (e && e.stopPropagation) {
							e.stopPropagation();
						}
					}
				}

				jQuery.extend({
					Deferred: function() {
						let tuples = [
								['resolve', 'done', jQuery.Callbacks('once memory'), 'resolved'],
								['reject', 'fail', jQuery.Callbacks('once memory'), 'rejected'],
								['notify', 'progress', jQuery.Callbacks('memory')]
							],
							state = 'pending',
							promise = {
								state: function() {
									return state;
								},
								then: function() {

								},
								promise: function(obj) {
									return obj != null ? jQuery.extend(obj, promise) : promise;
								}
							},
							deferred = {};

						tuples.forEach(function(tuple, i) {
							let list = tuple[2],
								stateString = tuple[3];

							promise[tuple[1]] = list.add;

							if (stateString) {
								list.add(function() {
									state = stateString
								});
							}

							deferred[tuple[0] + 'with'] = list.fireWith;
							deferred[tuple[0]] = function() {
								deferred[tuple[0] + 'with'](this === deferred ? promise : this, arguments);
								return this;
							}
						})

						promise.promise(deferred);

						return deferred;
					},

					// when: function (subordinate) {
					// 	return subordinate.promise();
					// }
					when: function(subordinate) {
						let der = jQuery.Deferred();
						subordinate(der.resolve, der.reject);
						return der;
					}
				});

				jQuery.fn.extend({
					each: function(callback, args) {
						return jQuery.each(this, callback, args);
					},

					on: function(types, fn) {
						let type;
						if (typeof types === 'object') {
							// 如果是objcet的话,说明是给多个事件绑定同一个函数
							for (type in types) {
								this.on(types[type], fn);
							}
						}
						// 循环绑定 event 事件
						return this.each(function() {
							jQuery.event.add(this, types, fn);
						})
					},

					trigger: function(type, data) {
						// 循环绑定 event.trigger 事件
						return this.each(function() {
							jQuery.event.trigger(type, data, this);
						})
					}
				})

				jQuery.fn.init.prototype = jQuery.fn

				root.$ = root.jQuery = jQuery;
			})(window)
		</script>
		<script>
			function wait() {
				let der = $.Deferred();

				function text() {
					console.log(111);
					der.resolve();
				}
				setTimeout(text, 2000)
				return der;
			}

			// $.when(wait())
			// 	.done(function (res) {
			// 		console.log('done');
			// 	})
			// 	.fail(function (res) {
			// 		console.log('fail');
			// 	})

			// 模拟Promise的使用方法
			$.when(function(res, rej) {
					console.log(111);
					setTimeout(res, 2000)
				})
				.done(function(res) {
					console.log('done');
				})
				.fail(function(res) {
					console.log('fail');
				})
		</script>
		<script>
			$('p').on('max', function(e, val) {
				console.log('p:',val);
			})
			$('#btn').on('max', function(e,val) {
				console.log('btn:',val);
			})
			$('#btn').trigger('max', 'haha')
		</script>
	</body>
</html>
